package com.jlpay.open.jlpay.sdk.java.http;

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jlpay.open.jlpay.sdk.java.exception.HttpExecutionException;
import com.jlpay.open.jlpay.sdk.java.exception.HttpStatusCodeException;
import com.jlpay.open.jlpay.sdk.java.sign.SignVerifierManager;
import okhttp3.*;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @author zhaomeixia
 * @since 2024/2/19
 */
public class OkHttpClientWrapper extends AbstractHttpClient {

    private final OkHttpClient client;

    public OkHttpClientWrapper(final OkHttpClient client, final SignVerifierManager signVerifierManager) {
        super(signVerifierManager);
        this.client = client;
    }

    @Override
    public HttpResponse sendPost(HttpRequest httpRequest) {
        RequestBody requestBody = RequestBody.create(httpRequest.getBody().getBytes(StandardCharsets.UTF_8));
        Request request = new Request.Builder()
                .url(httpRequest.getUrl())
                .headers(Headers.of(httpRequest.getHeaders()))
                .post(requestBody)
                .build();

        try (Response response = client.newCall(request).execute()) {
            HttpResponse httpResponse = buildHttpResponse(response);
            if (!response.isSuccessful()) {
                throw new HttpStatusCodeException(
                        httpResponse.getStatusCode(),
                        httpResponse.getBody(),
                        getHeaderRequestId(httpResponse.getHeaders())
                );
            }
            return httpResponse;
        } catch (IOException e) {
            throw new HttpExecutionException(String.format("Http Client execute failed, request: %s", httpRequest), e);
        }
    }

    @Override
    public HttpResponse sendGet(HttpRequest httpRequest) {
        Request request = new Request.Builder()
                .url(httpRequest.getUrl())
                .headers(Headers.of(httpRequest.getHeaders()))
                .get()
                .build();

        try (Response response = client.newCall(request).execute()) {
            HttpResponse httpResponse = buildHttpResponse(response);
            if (!response.isSuccessful()) {
                throw new HttpStatusCodeException(
                        httpResponse.getStatusCode(),
                        httpResponse.getBody(),
                        getHeaderRequestId(httpResponse.getHeaders())
                );
            }
            return httpResponse;
        } catch (IOException e) {
            throw new HttpExecutionException(String.format("Http Client execute failed, request: %s", httpRequest), e);
        }
    }

    @Override
    public HttpResponse sendFromPost(MultipartHttpRequest httpRequest) {
        ObjectNode meta = httpRequest.getMeta();
        // 准备文件部分
        RequestBody fileBody = RequestBody.create(MediaType.parse(JlpayHttpHeaders.MediaType.MULTIPART_FORM_DATA_VALUE),
                httpRequest.getFile());

        // 创建MultipartBody.Builder并添加meta和file部分
        MultipartBody.Builder multipartBuilder = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("meta", meta.toString())
                .addFormDataPart("file", meta.get("filename").textValue(), fileBody);

        // 构建MultipartBody
        MultipartBody multipartBody = multipartBuilder.build();

        // 创建Request
        Request request = new Request.Builder()
                .url(httpRequest.getUrl())
                .headers(Headers.of(httpRequest.getHeaders()))
                .post(multipartBody)
                .build();

        try (Response response = client.newCall(request).execute()) {
            HttpResponse httpResponse = buildHttpResponse(response);
            if (!response.isSuccessful()) {
                throw new HttpStatusCodeException(
                        httpResponse.getStatusCode(),
                        httpResponse.getBody(),
                        getHeaderRequestId(httpResponse.getHeaders())
                );
            }
            return httpResponse;
        } catch (IOException e) {
            throw new HttpExecutionException(String.format("Http Client execute failed, request: %s", httpRequest), e);
        }

    }

    private HttpResponse buildHttpResponse(Response response) throws IOException {
        Map<String, String> headerMap = new HashMap<>();
        response.headers().iterator().forEachRemaining(header -> headerMap.put(header.getFirst(), header.getSecond()));
        return HttpResponse.builder()
                .headers(headerMap)
                .body(getBody(response))
                .statusCode(response.code())
                .build();
    }

    private String getBody(Response response) throws IOException {
        return response.body() != null ? response.body().string() : null;
    }
}
